Import cal3d

Class CalCoreBone

	Field m_name:String
	Field m_coreSkeleton:CalCoreSkeleton
	Field m_parentId:Int
	Field m_listChildId:Int[]
	Field m_translation:CalVector
	Field m_rotation:CalQuaternion
	Field m_translationAbsolute:CalVector
	Field m_rotationAbsolute:CalQuaternion
	Field m_translationBoneSpace:CalVector
	Field m_rotationBoneSpace:CalQuaternion
	Field m_userData:Object
	Field m_boundingBox:CalBoundingBox
	Field m_boundingPosition:CalVector[]
	Field m_boundingBoxPrecomputed:Bool
	
	
	Method New(name:String="Bone")
	
		 m_name = name
		 m_coreSkeleton = Null
		 m_parentId = -1
		 m_listChildId = New Int[0]
		 m_translation = New CalVector()
		 m_rotation = New CalQuaternion()
		 m_translationAbsolute = New CalVector()
		 m_rotationAbsolute= New CalQuaternion()
		 m_translationBoneSpace = New CalVector()
		 m_rotationBoneSpace = New CalQuaternion()
		 m_userData = Null
		 m_boundingBox = New CalBoundingBox()
		 m_boundingPosition = New CalVector[6]
		 For Local i:Int = 0 To 5
		 	m_boundingPosition[i] = New CalVector
		 Next
		 m_boundingBoxPrecomputed = False		
	
	End
	
	Method addChildId:Bool(childId:Int)
		Local id:Int = m_listChildId.Length
		'Print "Add bone: "+id
		m_listChildId = m_listChildId.Resize(m_listChildId.Length+1)
		m_listChildId[id] = childId
		return true		
	End

	Method calculateState:Void()

		If m_parentId = -1 Then
			' no parent, this means absolute state == relative state
			m_translationAbsolute.assign(m_translation)
			m_rotationAbsolute.assign(m_rotation)
		
		Else 
			' get the parent bone
			Local parent:CalCoreBone = m_coreSkeleton.getCoreBone(m_parentId)
	
			' transform relative state with the absolute state of the parent
			m_translationAbsolute.assign(m_translation)
			m_translationAbsolute.multQuaternionLocal(parent.getRotationAbsolute())
			m_translationAbsolute.addLocal(parent.getTranslationAbsolute())
	
			m_rotationAbsolute.assign(m_rotation)
			m_rotationAbsolute.multQuaternionLocal(parent.getRotationAbsolute())
		Endif
	
		' calculate all child bones
		For Local iChildId:Int = 0 To m_listChildId.Length-1
			m_coreSkeleton.getCoreBone(m_listChildId[iChildId]).calculateState()
		Next		
	
	End
	
	Method getListChildId:Int[]()
		Return m_listChildId
	End
	
	Method getName:String()
		Return m_name
	End
	
	Method getParentId:Int()
		Return m_parentId
	End
	
	Method getCoreSkeleton:CalCoreSkeleton()
		Return m_coreSkeleton
	End
	
	Method getRotation:CalQuaternion()
		Return m_rotation
	End
	
	Method getRotationAbsolute:CalQuaternion()
		Return m_rotationAbsolute
	End
	
	Method getRotationBoneSpace:CalQuaternion()
		Return m_rotationBoneSpace
	End
	
	Method getTranslation:CalVector()
		Return m_translation
	End
	
	Method getTranslationAbsolute:CalVector()
		Return m_translationAbsolute
	End
	
	Method getTranslationBoneSpace:CalVector()
		Return m_translationBoneSpace
	End
	
	Method getUserData:Object()
		Return m_userData
	End

	Method setCoreSkeleton:Void(coreSkeleton:CalCoreSkeleton)
		m_coreSkeleton = coreSkeleton
	End
	
	Method setParentId:Void(parentId:Int)
		m_parentId = parentId
	End
	
	Method setRotation:Void(rotation:CalQuaternion)
		m_rotation.assign(rotation)
	End
	
	Method setRotationBoneSpace:Void(rotation:CalQuaternion)
		m_rotationBoneSpace.assign(rotation)
	End	

	Method setTranslation:Void(translation:CalVector)
		m_translation.assign(translation)
	End	

	Method setTranslationBoneSpace:Void(translation:CalVector)
		m_translationBoneSpace.assign(translation)
	End	
	
	Method setUserData:Void(userData:Object)
		m_userData = userData
	End

	Method calculateBoundingBox:Void(coreModel:CalCoreModel)
	
		Local boneId:Int = m_coreSkeleton.getCoreBoneId(m_name)
		Local bBoundsComputed:Bool = False
	
		Local rot:CalQuaternion = New CalQuaternion(m_rotationBoneSpace)
		rot.invert()
	
		Local dir:CalVector = New CalVector(1, 0, 0)
		dir.multQuaternionLocal(rot)
		m_boundingBox.plane[0].setNormal(dir)
	
		dir.assign(-1, 0, 0)
		dir.multQuaternionLocal(rot)
		m_boundingBox.plane[1].setNormal(dir)
	
		dir.assign(0, 1, 0)
		dir.multQuaternionLocal(rot)
		m_boundingBox.plane[2].setNormal(dir)
	
		dir.assign(0, -1, 0)
		dir.multQuaternionLocal(rot)
		m_boundingBox.plane[3].setNormal(dir)
	
		dir.assign(0, 0, 1)
		dir.multQuaternionLocal(rot)
		m_boundingBox.plane[4].setNormal(dir)
	
		dir.assign(0, 0, -1)
		dir.multQuaternionLocal(rot)
		m_boundingBox.plane[5].setNormal(dir)
	
		Local coreMeshCount:int = coreModel.getCoreMeshCount()
		For Local meshId:Int = 0 To coreMeshCount-1
			Local coreMesh:CalCoreMesh = coreModel.getCoreMesh(meshId)
	
			Local coreSubmeshCount:Int = coreMesh.getCoreSubmeshCount()
			For Local submeshId:Int = 0 To coreSubmeshCount-1
				Local coreSubmesh:CalCoreSubmesh = coreMesh.getCoreSubmesh(submeshId)
	
				If coreSubmesh.getSpringCount() = 0 then
					local vectorVertex:CalVertex[] = coreSubmesh.getVectorVertex()
					For Local vertexId:Int = 0 To vectorVertex.Length-1
						Local vertexInfluenceCount:Int = vectorVertex[vertexId].vectorInfluence.Length
						For Local influenceId:Int = 0 To vertexInfluenceCount-1
							If vectorVertex[vertexId].vectorInfluence[influenceId].boneId = boneId And vectorVertex[vertexId].vectorInfluence[influenceId].weight > 0.5 then
								For Local planeId:Int = 0 To 5
									If m_boundingBox.plane[planeId].eval(vectorVertex[vertexId].position) < 0 Then
										m_boundingBox.plane[planeId].setPosition(vectorVertex[vertexId].position)
										m_boundingPosition[planeId].assign(vectorVertex[vertexId].position)
										bBoundsComputed = true
									Endif
								Next
							Endif
						Next
					Next	
				Endif
			next
		Next
	
		' to handle bones with no vertices assigned 
		If bBoundsComputed = False then
			For Local planeId:Int = 0 To 5
				m_boundingBox.plane[planeId].setPosition(m_translation) 
				m_boundingPosition[planeId].assign(m_translation) 
			Next 
		Endif
	
		m_boundingBoxPrecomputed = true	
	
	End
	
	Method getBoundingBox:CalBoundingBox()
		Return m_boundingBox
	End
	
	Method getBoundingData:CalVector(planeId:Int, position:CalVector)
		
		If position = Null then
			position = new CalVector
		Endif
		position.assign(m_boundingPosition[planeId])
		return position	
	End
	
	Method isBoundingBoxPrecomputed:Bool()
		Return m_boundingBoxPrecomputed
	End
	
	Method scale:Void(factor:Float)
	
		m_translation.multScalarLocal(factor)
		m_translationAbsolute.multScalarLocal(factor)
		m_translationBoneSpace.multScalarLocal(factor)
	
		' calculate all child bones
		For Local iChildId:Int = 0 To m_listChildId.Length
			m_coreSkeleton.getCoreBone(m_listChildId[iChildId]).scale(factor)
		Next
	
	End
	
	

End Class

